package com.wiscamp.ninechapters.panels.adapter.resources;

import com.wiscamp.ninechapters.panels.application.command.LoginCommand;
import com.wiscamp.ninechapters.panels.application.dto.JwtToken;
import com.wiscamp.ninechapters.panels.application.services.RoleAppService;
import com.wiscamp.ninechapters.panels.application.services.UserAppService;
import com.wiscamp.ninechapters.panels.application.vo.RoleVO;
import com.wiscamp.ninechapters.panels.application.vo.UserVO;
import cube.common.security.jwt.JwtUtilities;
import cube.ddd.adapter.BaseController;
import cube.ddd.adapter.RestResponse;
import cube.ddd.utils.ResourceUtils;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import jakarta.ws.rs.core.Context;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.stream.Collectors;

/**
 * Controller to authenticate users.
 */
@RestController
@RequestMapping("/api/ControlPanels")
@Tag(name = "控制面板-用户认证")
public class AuthenticationController extends BaseController {

    private final JwtUtilities tokenProvider;

    private final AuthenticationManagerBuilder authenticationManagerBuilder;

    private final UserAppService userAppService;

    private final RoleAppService roleAppService;

    public AuthenticationController(JwtUtilities tokenProvider, AuthenticationManagerBuilder authenticationManagerBuilder, UserAppService userAppService, RoleAppService roleAppService) {
        this.tokenProvider = tokenProvider;
        this.authenticationManagerBuilder = authenticationManagerBuilder;
        this.userAppService = userAppService;
        this.roleAppService = roleAppService;
    }

    @PostMapping("/Authenticate")
    public RestResponse<JwtToken> authenticate(@Context HttpServletRequest request, @Context HttpServletResponse response, @Valid @RequestBody LoginCommand command) {
        var appIdAndUserCode = command.getApplicationId() + "::" + command.getUserCode();
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(appIdAndUserCode, command.getPassword());

      /*var currentUser = (CurrentUser) customerUserDetailsService.loadUserByUsername(appIdAndUserCode);
      authenticationToken.setDetails(currentUser);*/
        Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);

        SecurityContextHolder.getContext().setAuthentication(authentication);

        UserVO loginUser = userAppService.getUserByCode(command.getApplicationId(), command.getUserCode());
        long tenantId = 0; // 暂时不考虑多租户管理

        var roleIds = userAppService.getUserRoleIds(loginUser.getUserId());
        var roles = roleAppService.getRolesByIds(roleIds);
        var roleCodes = roles.stream().map(RoleVO::getRoleCode).collect(Collectors.toList());
        roleCodes.add("ADMIN");

        boolean rememberMe = (command.isRememberMe() == null) ? false : command.isRememberMe();
        String jwt = tokenProvider.generateToken(appIdAndUserCode, rememberMe, command.getApplicationId(),
                tenantId, loginUser.getUserId(), loginUser.getUserCode(), loginUser.getUserName(), roleCodes);

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add("Authorization", "Bearer " + jwt);

        var jwtToken = new JwtToken(loginUser.getApplicationId(), tenantId, loginUser.getUserId(), loginUser.getUserName(), jwt);
        return ResourceUtils.getOkResponse(request, response, jwtToken);
    }
}
